﻿using System;
using System.Collections.ObjectModel;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using VioletDevelopmentLaboratory.Net.Data;
using VioletDevelopmentLaboratory.Net.Web.Configuration;
using System.Web;
using System.Text;
using System.Net;
using System.IO;
using System.Xml;
using System.Xml.XPath;

namespace VioletDevelopmentLaboratory.Net.Web.Component
{
	public enum TrackbackAddResult { Success, Exists, Failure }
	public enum TrackbackRemoveResult { Success, Failure }
	public enum TrackbackSendResult { Success = 0, Failure }

	public class Trackback
	{
		private Trackback() { }

		private String applicationName;
		public String ApplicationName { get { return this.applicationName; } }

		private String componentID;
		public String ComponentID { get { return this.componentID; } }

		private String relationID;
		public String RelationID { get { return this.relationID; } }

		private String trackbackID;
		public String TrackbackID { get { return this.trackbackID; } }

		private String url;
		public String Url { get { return this.url; } }

		private String blogName;
		public String BlogName { get { return this.blogName; } }

		private String title;
		public String Title { get { return this.title; } }

		private String excerpt;
		public String Excerpt { get { return this.excerpt; } }

		private DateTime registrationDate;
		public DateTime RegistrationDate { get { return this.registrationDate; } }

		public static TrackbackAddResult Add(String componentID, String relationID, String url, String blogName, String title, String excerpt)
		{
			if (componentID == null)
				throw new ArgumentNullException("componentID");

			if (relationID == null)
				throw new ArgumentNullException("relationID");

			if (url == null)
				throw new ArgumentNullException("url");

			if (blogName == null)
				throw new ArgumentNullException("blogName");

			if (title == null)
				throw new ArgumentNullException("title");

			if (excerpt == null)
				throw new ArgumentNullException("excerpt");

			if (String.IsNullOrEmpty(componentID))
				throw new ArgumentOutOfRangeException("componentID");

			if (String.IsNullOrEmpty(relationID))
				throw new ArgumentOutOfRangeException("relationID");

			if (String.IsNullOrEmpty(url))
				throw new ArgumentOutOfRangeException("url");

			if (String.IsNullOrEmpty(blogName))
				throw new ArgumentOutOfRangeException("blogName");
	
			if (String.IsNullOrEmpty(title))
				throw new ArgumentOutOfRangeException("title");
			
			if (String.IsNullOrEmpty(excerpt))
				throw new ArgumentOutOfRangeException("excerpt");
			
			if (!VUtility.IsGuid(relationID))
				throw new FormatException("relationID must Guid.");

			Object returnValue = null;

			SqlClientAgent.ExecuteNonQuery(
				ConfigurationManager.ConnectionStrings[VWebConfigurationReader.ConnectionStringName].ConnectionString,
				CommandType.StoredProcedure,
				"VWeb_Trackback_Create",
				out returnValue,
				new SqlParameter("@ApplicationName", VWebConfigurationReader.ApplicationName),
				new SqlParameter("@ComponentID", componentID),
				new SqlParameter("@RelationID", relationID),
				new SqlParameter("@Url", url),
				new SqlParameter("@BlogName", blogName),
				new SqlParameter("@Title", title),
				new SqlParameter("@Excerpt", excerpt)
			);

			switch ((Int32)returnValue)
			{
				case 0:
					return TrackbackAddResult.Success;
				case 1:
					return TrackbackAddResult.Failure;
				case 2:
					return TrackbackAddResult.Exists;
				default:
					return TrackbackAddResult.Failure;
			}
		}

		public static TrackbackRemoveResult Remove(String componentID, String trackbackID)
		{
			if (componentID == null)
				throw new ArgumentNullException("componentID");

			if (trackbackID == null)
				throw new ArgumentNullException("trackbackID");

			if (String.IsNullOrEmpty(componentID))
				throw new ArgumentOutOfRangeException("componentID");

			if (String.IsNullOrEmpty(trackbackID))
				throw new ArgumentOutOfRangeException("trackbackID");

			if (!VUtility.IsGuid(trackbackID))
				throw new FormatException("trackbackID must Guid.");

			Object returnValue = null;

			SqlClientAgent.ExecuteNonQuery(
				ConfigurationManager.ConnectionStrings[VWebConfigurationReader.ConnectionStringName].ConnectionString,
				CommandType.StoredProcedure,
				"VWeb_Trackback_Delete",
				out returnValue,
				new SqlParameter("@ApplicationName", VWebConfigurationReader.ApplicationName),
				new SqlParameter("@ComponentID", componentID),
				new SqlParameter("@TrackbackID", trackbackID)
			);

			switch ((Int32)returnValue)
			{
				case 0:
					return TrackbackRemoveResult.Success;
				default:
					return TrackbackRemoveResult.Failure;
			}
		}

		public static TrackbackRemoveResult RemoveAll()
		{
			Object returnValue = null;

			SqlClientAgent.ExecuteNonQuery(
				ConfigurationManager.ConnectionStrings[VWebConfigurationReader.ConnectionStringName].ConnectionString,
				CommandType.StoredProcedure,
				"VWeb_Trackback_DeleteAllByApplicationName",
				out returnValue,
				new SqlParameter("@ApplicationName", VWebConfigurationReader.ApplicationName)
			);

			switch ((Int32)returnValue)
			{
				case 0:
					return TrackbackRemoveResult.Success;
				default:
					return TrackbackRemoveResult.Failure;
			}
		}

		public static TrackbackRemoveResult RemoveAll(String componentID)
		{
			if (componentID == null)
				throw new ArgumentNullException("componentID");

			if (String.IsNullOrEmpty(componentID))
				throw new ArgumentOutOfRangeException("componentID");

			Object returnValue = null;

			SqlClientAgent.ExecuteNonQuery(
				ConfigurationManager.ConnectionStrings[VWebConfigurationReader.ConnectionStringName].ConnectionString,
				CommandType.StoredProcedure,
				"VWeb_Trackback_DeleteAllByComponentID",
				out returnValue,
				new SqlParameter("@ApplicationName", VWebConfigurationReader.ApplicationName),
				new SqlParameter("@ComponentID", componentID)
			);

			switch ((Int32)returnValue)
			{
				case 0:
					return TrackbackRemoveResult.Success;
				default:
					return TrackbackRemoveResult.Failure;
			}
		}

		public static TrackbackRemoveResult RemoveAll(String componentID, String relationID)
		{
			if (componentID == null)
				throw new ArgumentNullException("componentID");

			if (relationID == null)
				throw new ArgumentNullException("relationID");

			if (String.IsNullOrEmpty(componentID))
				throw new ArgumentOutOfRangeException("componentID");

			if (String.IsNullOrEmpty(relationID))
				throw new ArgumentOutOfRangeException("relationID");

			if (!VUtility.IsGuid(relationID))
				throw new FormatException("relationID must Guid.");

			Object returnValue = null;

			SqlClientAgent.ExecuteNonQuery(
				ConfigurationManager.ConnectionStrings[VWebConfigurationReader.ConnectionStringName].ConnectionString,
				CommandType.StoredProcedure,
				"VWeb_Trackback_DeleteAllByRelationID",
				out returnValue,
				new SqlParameter("@ApplicationName", VWebConfigurationReader.ApplicationName),
				new SqlParameter("@ComponentID", componentID),
				new SqlParameter("@RelationID", relationID)
			);

			switch ((Int32)returnValue)
			{
				case 0:
					return TrackbackRemoveResult.Success;
				default:
					return TrackbackRemoveResult.Failure;
			}
		}

		private static Trackback fill(SqlDataReader reader)
		{
			Trackback trackback = new Trackback();
			trackback.applicationName = reader["ApplicationName"].ToString();
			trackback.componentID = reader["ComponentID"].ToString();
			trackback.relationID = reader["RelationID"].ToString();
			trackback.trackbackID = reader["TrackbackID"].ToString();
			trackback.url = reader["Url"].ToString();
			trackback.blogName = reader["BlogName"].ToString();
			trackback.title = reader["Title"].ToString();
			trackback.excerpt = reader["Excerpt"].ToString();
			trackback.registrationDate = (DateTime)reader["RegistrationDate"];

			return trackback;
		}

		internal static Trackback Fill(DataRow row)
		{
			Trackback trackback = new Trackback();
			trackback.applicationName = row["ApplicationName"].ToString();
			trackback.componentID = row["ComponentID"].ToString();
			trackback.relationID = row["RelationID"].ToString();
			trackback.trackbackID = row["TrackbackID"].ToString();
			trackback.url = row["Url"].ToString();
			trackback.blogName = row["BlogName"].ToString();
			trackback.title = row["Title"].ToString();
			trackback.excerpt = row["Excerpt"].ToString();
			trackback.registrationDate = (DateTime)row["RegistrationDate"];

			return trackback;
		}

		public static TrackbackCollection GetTrackbackCollection(String componentID, String relationID)
		{
			if (componentID == null)
				throw new ArgumentNullException("componentID");

			if (relationID == null)
				throw new ArgumentNullException("relationID");

			if (String.IsNullOrEmpty(componentID))
				throw new ArgumentOutOfRangeException("componentID");

			if (String.IsNullOrEmpty(relationID))
				throw new ArgumentOutOfRangeException("relationID");

			if (!VUtility.IsGuid(relationID))
				throw new FormatException("relationID must Guid.");

			SqlDataReader reader = SqlClientAgent.ExecuteReader(
				ConfigurationManager.ConnectionStrings[VWebConfigurationReader.ConnectionStringName].ConnectionString,
				CommandType.StoredProcedure,
				"VWeb_Trackback_GetTrackbacksByRelationID",
				new SqlParameter("@ApplicationName", VWebConfigurationReader.ApplicationName),
				new SqlParameter("@ComponentID", componentID),
				new SqlParameter("@RelationID", relationID)
			);

			TrackbackCollection trackbacks = null;

			try
			{
				if (reader.HasRows)
				{
					trackbacks = new TrackbackCollection();

					while (reader.Read())
					{
						trackbacks.Add(fill(reader));
					}
				}
			}
			finally
			{
				reader.Close();
			}

			return trackbacks;
		}

		public static TrackbackSendResult Send(String trackbackUrl, String url, String blogName, String title, String excerpt, Encoding encoding, out String message)
		{
			String parameters = String.Format("url={0}&blog_name={1}&title={2}&excerpt={3}",
				HttpUtility.UrlEncode(url, encoding),
				HttpUtility.UrlEncode(blogName, encoding),
				HttpUtility.UrlEncode(title, encoding),
				HttpUtility.UrlEncode(VUtility.RemoveHtmlTag(excerpt), encoding)
			);

			HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(trackbackUrl);
			webRequest.Method = "POST";
			webRequest.Timeout = 10000;
			webRequest.ContentType = String.Format("application/x-www-form-urlencoded; charset={0}", encoding.CodePage);
			webRequest.ContentLength = parameters.Length;

			TrackbackSendResult result = TrackbackSendResult.Failure;
			message = "";

			try
			{
				using (StreamWriter streamWriter = new StreamWriter(webRequest.GetRequestStream()))
				{
					streamWriter.Write(parameters);
				}

				using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse())
				{
					String resultXmlString = "";

					using (StreamReader streamReader = new StreamReader(webResponse.GetResponseStream()))
					{
						resultXmlString = streamReader.ReadToEnd();
					}

					XmlDocument resultXml = new System.Xml.XmlDocument();
					resultXml.LoadXml(resultXmlString.Trim());

					XPathNavigator xnav = resultXml.CreateNavigator();

					if (webResponse.StatusCode >= HttpStatusCode.OK && webResponse.StatusCode < HttpStatusCode.Ambiguous)
					{
						try
						{
							result = (TrackbackSendResult)Enum.Parse(typeof(TrackbackSendResult), xnav.SelectSingleNode("response/error").Value);
						}
						catch
						{
							result = TrackbackSendResult.Failure;
						}
					}
					else
					{
						result = TrackbackSendResult.Failure;
					}

					xnav = xnav.SelectSingleNode("response/message");
					message = xnav != null ? xnav.Value : String.Empty;
				}
			}
			catch (Exception ex)
			{
				result = TrackbackSendResult.Failure;
				message = ex.Message;
			}

			return result;
		}
	}

	public class TrackbackCollection : Collection<Trackback> { }
}
